package com.zkh.myutils.extension.image;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.ImageIO;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.zkh.myutils.io.log.Logger;
import com.zkh.myutils.utils.UtilsException;

/**
 * 使用Zxing包生成和解析二维码。
 * @author zkh
 */
public class ZxingCode {
	//容错率常量
	/**
	 * 容错率高
	 */
	public final static ErrorCorrectionLevel LEVEL_HEIGHT = ErrorCorrectionLevel.H;
	/**
	 * 容错率较高
	 */
	public final static ErrorCorrectionLevel LEVEL_QUALITY = ErrorCorrectionLevel.Q;
	/**
	 * 容错率中等、一般
	 */
	public final static ErrorCorrectionLevel LEVEL_MIDDLE = ErrorCorrectionLevel.M;
	/**
	 * 容错率低
	 */
	public final static ErrorCorrectionLevel LEVEL_LOWER = ErrorCorrectionLevel.L;
	
	//二维码宽高
	private int width = 150;
	private int height = 150;
	//二维码颜色
	private Color bgColor = Color.WHITE;
	private Color fgColor = Color.BLACK;
	//容错率
	private ErrorCorrectionLevel level = ErrorCorrectionLevel.M;

	/**
	 * 二维码构造方法，使用默认宽高：150 X 150
	 */
	public ZxingCode(){
	}
	
	/**
	 * 二维码构造方法
	 * @param width 二维码宽度
	 * @param height 二维码高度
	 */
	public ZxingCode(int width, int height){
		this.width = width;
		this.height = height;
	}
	
	/**
	 * 设置二维码背景色，默认为白色
	 * @param bgColor 背景色
	 */
	public void setBgColor(Color bgColor) {
		this.bgColor = bgColor;
	}
	
	/**
	 * 设置二维码前景色，默认为黑色
	 * @param fgColor 前景色
	 */
	public void setFgColor(Color fgColor) {
		this.fgColor = fgColor;
	}
	
	/**
	 * 设置容错级别
	 * @param level 容错级别，通过常量 LEVEL_* 设置。
	 */
	public void setLevel(ErrorCorrectionLevel level){
		this.level = level;
	}
	
	/**
	 * 生成二维码
	 * @param content 二维码内容
	 */
	public BufferedImage create(String content){
		//二维码属性容器
		Map<EncodeHintType, Object> his = new HashMap<EncodeHintType, Object>();
		//设置编码字符集
		his.put(EncodeHintType.CHARACTER_SET, "utf-8");
		//设置边距
		his.put(EncodeHintType.MARGIN, 0);
		his.put(EncodeHintType.ERROR_CORRECTION, level);
		try{
			//生成二维码
			BitMatrix encode = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, his);
			
			//获取二维码宽高
			int codeWidth = encode.getWidth();
			int codeHeight = encode.getHeight();
			//缓存图片
			BufferedImage image = new BufferedImage(codeWidth, codeHeight, BufferedImage.TYPE_INT_RGB);
			//将二维码写入图片
			for(int i = 0; i<codeWidth; i++) {
				for(int j = 0; j<codeHeight; j++) {
					//循环将二维码内容写入图片
					image.setRGB(i, j, encode.get(i, j) ? fgColor.getRGB() : bgColor.getRGB());
				}
			}
			//返回缓存图片
			return image;
		} catch (WriterException e) {
			Logger.error(e);
			throw new RuntimeException("二维码生成失败");
		}
	}
	
	/**
	 * 生成带图标的二维码。图标与二维码之间的间距默认5px
	 * @param content 二维码内容
	 * @param iconpath 二维码中心图标路径
	 */
	public BufferedImage create(String content, String iconpath){
		return create(content, iconpath, 5);
	}
	
	/**
	 * 生成带图标的二维码
	 * @param content 二维码内容
	 * @param iconpath 二维码中心图标路径
	 * @param padding 图标与二维码之间的间距，单位px
	 */
	public BufferedImage create(String content, String iconpath, int padding){
		//判断图标是否存在
		File icon = new File(iconpath);
		try{
			//存在
			if(icon.exists()){
				return create(content, ImageIO.read(icon), padding);
			}
		}catch(IOException e){
			Logger.error(e);
		}
		return null;
	}
	
	/**
	 * 生成带图标的二维码。图标与二维码之间的间距默认5px
	 * @param content 二维码内容
	 * @param icon 二维码中心图标资源
	 */
	public BufferedImage create(String content, BufferedImage icon){
		return create(content, icon, 5);
	}
	
	/**
	 * 生成带图标的二维码。
	 * @param content 二维码内容
	 * @param icon 二维码中心图标资源
	 * @param padding 图标与二维码之间的间距，单位px
	 */
	public BufferedImage create(String content, BufferedImage icon, int padding){
		//生成二维码
		BufferedImage bi = create(content);
		//原二维码宽高
		int oWidth = bi.getWidth();
		int oHeight = bi.getHeight();
		//图标宽高
		int iWidth = icon.getWidth();
		int iHeight = icon.getHeight();
		//检查
		if(iWidth>oWidth*0.67 || iHeight>oHeight*0.67){
			throw new UtilsException("图标宽高不能超过二维码宽高的2/3");
		}
		//获取二维码画布
		Graphics2D g = bi.createGraphics();
		//位置
		int left = (oWidth-iWidth)/2;
		int top = (oHeight-iHeight)/2;
		//矩形颜色
		g.setColor(Color.BLACK);
		//画矩形
		g.drawRect(left-padding-1, top-padding-1, iWidth+padding*2+1, iHeight+padding*2+1);
		//背景
		g.setBackground(Color.WHITE);
		//在二维码上留空
		g.clearRect(left-padding, top-padding, iWidth+padding*2, iHeight+padding*2);
		//在二维码上画图标
		g.drawImage(icon, left, top, iWidth, iHeight, null);
		//销毁资源
		g.dispose();
		//返回值
		return bi;
	}
	
	/**
	 * 将缓存图片写入到输出流
	 * @param bi 缓存图片对象
	 * @param os 输出流
	 */
	public void output(BufferedImage bi, OutputStream os){
		try {
			ImageIO.write(bi, "png", os);
		} catch (IOException e) {
			Logger.error(e);
		}
	}
}
